package com.zhiletu.collect.util;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;

/**
 *
 * @Title: 编码解析工具类
 * @Package com.zhiletu.collect.util
 * @Description: 根据内容判断内容编码
 * @author zhiletu.com
 * @date 2021年3月11日
 * @version V1.0
 */
public class EncodeParseUtil {

	/**
	 * 读取文本文件的编码
	 * @param in
	 * @return
	 * @throws IOException
	 */
	public String getTxtEncode(FileInputStream in) throws IOException {

		//String dc  = Charset.defaultCharset().name();
		UnicodeInputStream uin = new UnicodeInputStream(in);

		if ("UTF-8".equals(uin.getEncoding())) {
			uin.close();
			return "UTF-8";
		}
		uin.close();

		byte[] head = new byte[3];
		in.read(head);
		String code = "GBK";
		if (head[0] == -1 && head[1] == -2)
			code = "UTF-16";
		if (head[0] == -2 && head[1] == -1)
			code = "Unicode";
		//带BOM
		if (head[0] == -17 && head[1] == -69 && head[2] == -65)
			code = "UTF-8";
		if ("Unicode".equals(code)) {
			code = "UTF-16";
		}
		return code;
	}

	/**
	 * 获取输入流的编码
	 * @param in
	 * @param closeflag 是否关闭
	 * @return
	 * @throws IOException
	 */
	public String getInputStreamEncode(InputStream in, boolean closeflag) throws IOException {

		//String dc  = Charset.defaultCharset().name();
		UnicodeInputStream uin = new UnicodeInputStream(in);

		return uin.getEncoding();

//		        byte[] head = new byte[3];  
//		        in.read(head);    
//		        String code = "GBK";  
//		        if (head[0] == -1 && head[1] == -2 )  
//		            code = "UTF-16";  
//		        if (head[0] == -2 && head[1] == -1 )  
//		            code = "Unicode";
//		        //带BOM
//		        if(head[0]==-17 && head[1]==-69 && head[2] ==-65)  
//		            code = "UTF-8";   		        
//		        if("Unicode".equals(code)){
//		         code = "UTF-16";
//		        }
//		        return code;
	}
}


/**
 * This inputstream will recognize unicode BOM marks and will skip bytes if 
 * getEncoding() method is called before any of the read(...) methods. 
 *
 * Usage pattern: String enc = "ISO-8859-1"; // or NULL to use systemdefault 
 * FileInputStream fis = new FileInputStream(file); UnicodeInputStream uin = new 
 * UnicodeInputStream(fis, enc); enc = uin.getEncoding(); // check and skip 
 * possible BOM bytes InputStreamReader in; if (enc == null) in = new 
 * InputStreamReader(uin); else in = new InputStreamReader(uin, enc); 
 */
class UnicodeInputStream extends InputStream {
	private static final int BOM_SIZE = 4096;

	PushbackInputStream internalIn;

	boolean isInited = false;

	String defaultEnc;

	String encoding;

	public UnicodeInputStream(InputStream in) {
		internalIn = new PushbackInputStream(in, BOM_SIZE);
		this.defaultEnc = "ISO-8859-1";
	}

	public String getDefaultEncoding() {
		return defaultEnc;
	}

	public String getEncoding() {
		if (!isInited) {
			try {
				init();
			}
			catch (IOException ex) {
				IllegalStateException ise = new IllegalStateException(
						"Init method failed.");
				ise.initCause(ise);
				throw ise;
			}
		}
		return encoding;
	}

	/**
	 * Read-ahead four bytes and check for BOM marks. Extra bytes are unread
	 * back to the stream, only BOM bytes are skipped.
	 */
	protected void init() throws IOException {
		if (isInited)
			return;

		byte bom[] = new byte[BOM_SIZE];
		int n, unread;
		n = internalIn.read(bom, 0, bom.length);

		String chars = new String(bom, this.defaultEnc).toLowerCase().trim();
		int s = 0;
		String chs = "charset=\"";
		if ((s = chars.indexOf(chs)) > -1) {// 先使用土法
			String chart = chars.substring(s + chs.length());
			if (chart.indexOf("\"") > -1) {
				encoding = chart.substring(0, chart.indexOf("\"")).trim();
			}
			unread = n;
		}
		else if ((s = chars.indexOf("charset=")) > -1) {// 先使用土法
			chs = "charset=";
			String chart = chars.substring(s + chs.length());
			if (chart.indexOf("\"") > -1) {
				encoding = chart.substring(0, chart.indexOf("\"")).trim();
			}
			unread = n;
		}

		else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00)
				&& (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
			encoding = "UTF-32BE";
			unread = n - 4;
		}
		else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)
				&& (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
			encoding = "UTF-32LE";
			unread = n - 4;
		}
		else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB)
				&& (bom[2] == (byte) 0xBF)) {
			encoding = "UTF-8";
			unread = n - 3;
		}
		else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
			encoding = "UTF-16BE";
			unread = n - 2;
		}
		else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
			encoding = "UTF-16LE";
			unread = n - 2;
		}
		else {
			// Unicode BOM mark not found, unread all bytes  默认值不能是上述utf系列的编码，否则逻辑混乱
			encoding = defaultEnc;
			unread = n;
		}
		// System.out.println("read=" + n + ", unread=" + unread);

		if (unread > 0)
			internalIn.unread(bom, (n - unread), unread);

		isInited = true;
	}

	public void close() throws IOException {
		// init();
		isInited = true;
		internalIn.close();
	}

	public int read() throws IOException {
		// init();
		isInited = true;
		return internalIn.read();
	}
}
